package com.xjoyt.pay.gateway.controllers;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

import javax.validation.constraints.NotNull;

import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import com.xjoyt.pay.commons.SignUtils;
import com.xjoyt.pay.dto.ExecuteResult;
import com.xjoyt.pay.gateway.constants.RedisConstant;
import com.xjoyt.pay.gateway.dto.TokenResult;
import com.xjoyt.pay.gateway.interfaces.MainContract;
import com.xjoyt.pay.gateway.params.TokenParam;
import com.xjoyt.pay.master.interfaces.DistributorContract;
import com.xjoyt.pay.master.interfaces.DistributorPreferenceContract;
import com.xjoyt.pay.master.interfaces.MerchantContract;
import com.xjoyt.pay.master.po.Distributor;
import com.xjoyt.pay.master.po.DistributorPreference;
import com.xjoyt.pay.master.po.Merchant;

@RestController
public class MainController extends GatewayAbstractController
        implements MainContract {

    @Autowired
    private MerchantContract merchantContract;

    @Autowired
    private DistributorContract distributorContract;

    @Autowired
    private DistributorPreferenceContract distributorPreferenceContract;

    @Override
    public ExecuteResult<TokenResult> getMerchantAccessToken(
            @RequestBody(required = false) TokenParam tokenParam) {

        Map<String, String> map = new HashMap<>();
        for (Field field : tokenParam.getClass().getFields()) {
            try {
                Object object = field.get(tokenParam);
                if (!"sign".equals(field.getName()) && object != null
                        && StringUtils.isNotBlank(object.toString())) {
                    map.put(field.getName(), object.toString());
                }

                if (!field.isAnnotationPresent(NotNull.class))
                    continue;

                if (object == null || StringUtils.isBlank(object.toString())) {
                    return ExecuteResult.fail("[" + field.getName() + "]是必填参数");
                }
            } catch (Exception e) {
                e.printStackTrace();
                return ExecuteResult.fail("服务器出错：验证参数出错");
            }
        }

        Merchant entity = merchantContract.getByNo(tokenParam.merchantNo);
        if (entity == null)
            return ExecuteResult.fail("商户号不存在");

        if (BooleanUtils.isNotTrue(entity.enabled))
            return ExecuteResult.fail("商户已被停用");

        if (entity.distributor == null
                || BooleanUtils.isNotTrue(entity.distributor.enabled))
            return ExecuteResult.fail("代理商已被停用");

        if (entity.distributor.company == null
                || BooleanUtils.isNotTrue(entity.distributor.company.enabled))
            return ExecuteResult.fail("公司已被停用");

        int size = redisTemplate.keys(RedisConstant.REDIS_KEY_ACCESS_TOKEN
                + "merchant." + tokenParam.merchantNo).size();
        int maxSize = 5000;
        if (size > maxSize) {
            return ExecuteResult.fail("已超过获取访问令牌的次数");
        }

        DistributorPreference preference = distributorPreferenceContract
                .get(entity.distributor.id);
        if (StringUtils.isNotBlank(tokenParam.token)
                && !tokenParam.token.equals(preference.token))
            return ExecuteResult.fail("令牌不正确");
        try {
            String signature = SignUtils
                    .getSignature(map, entity.key, preference.signType)
                    .toUpperCase();
            if (!tokenParam.sign.equals(signature)) {
                return ExecuteResult.fail("签名不正确");
            }
        } catch (Exception e) {
            e.printStackTrace();
            return ExecuteResult.fail("服务器出错：验证签名出错");
        }
        String accessToken = createAccessToken(entity);
        TokenResult result = new TokenResult();
        result.accessToken = accessToken;
        result.count = size;
        result.maxCount = maxSize;
        result.expireTime = RedisConstant.REDIS_COOLDOWN_TIME_ACCESS_TOKEN
                * 3600;
        return ExecuteResult.ok(result);
    }

    @Override
    public ExecuteResult<TokenResult> getDistributorAccessToken(
            @RequestBody(required = false) TokenParam tokenParam) {
        Map<String, String> map = new HashMap<>();
        for (Field field : tokenParam.getClass().getFields()) {
            try {
                Object object = field.get(tokenParam);
                if (!"sign".equals(field.getName()) && object != null
                        && StringUtils.isNotBlank(object.toString())) {
                    map.put(field.getName(), object.toString());
                }

                if (!field.isAnnotationPresent(NotNull.class))
                    continue;

                if (object == null || StringUtils.isBlank(object.toString())) {
                    return ExecuteResult.fail("[" + field.getName() + "]是必填参数");
                }
            } catch (Exception e) {
                e.printStackTrace();
                return ExecuteResult.fail("服务器出错：验证参数出错");
            }
        }

        int size = redisTemplate.keys(RedisConstant.REDIS_KEY_ACCESS_TOKEN
                + "distributor." + tokenParam.merchantNo).size();
        int maxSize = 2000;
        if (size > maxSize) {
            return ExecuteResult.fail("已超过获取访问令牌的次数");
        }

        Distributor entity = distributorContract.getByNo(tokenParam.merchantNo);
        if (entity == null)
            return ExecuteResult.fail("代理商号不存在");

        if (BooleanUtils.isNotTrue(entity.enabled))
            return ExecuteResult.fail("代理商已被停用");

        if (entity.company == null
                || BooleanUtils.isNotTrue(entity.company.enabled))
            return ExecuteResult.fail("公司已被停用");

        DistributorPreference preference = distributorPreferenceContract
                .get(entity.id);
        if (StringUtils.isNotBlank(tokenParam.token)
                && !tokenParam.token.equals(preference.token))
            return ExecuteResult.fail("令牌不正确");

        try {
            String signature = SignUtils
                    .getSignature(map, entity.key, preference.signType)
                    .toUpperCase();
            if (!tokenParam.sign.equals(signature)) {
                return ExecuteResult.fail("签名不正确");
            }
        } catch (Exception e) {
            e.printStackTrace();
            return ExecuteResult.fail("服务器出错：验证签名出错");
        }
        String accessToken = createAccessToken(entity);
        TokenResult result = new TokenResult();
        result.accessToken = accessToken;
        result.count = size;
        result.maxCount = maxSize;
        result.expireTime = RedisConstant.REDIS_COOLDOWN_TIME_ACCESS_TOKEN
                * 3600;
        return ExecuteResult.ok(result);
    }
}
